#ifndef _M_LOOP_H_
#define _M_LOOP_H_
/*实现异步工作器*/
/*外界将任务数据添加到输入缓冲区，异步线程对处理缓冲区中数据进行处理，若处理缓冲区中没有数据了则交换缓冲区*/ 
#include "buffer.hpp"
#include <mutex>
#include <condition_variable>
#include <functional>
#include <memory>
#include <thread>
#include <atomic>
namespace mylog{
using Functor=std::function<void(Buffer &)>;
enum class AsyncType{
 ASYNC_SAFE,  //安全状态，表示缓冲区满了则阻塞，避免资源耗尽的风险
 ASYNC_UNSAFE  //不考虑资源耗尽的问题
};
class AsyncLooper{
public:
using ptr=std::shared_ptr<AsyncLooper>;
AsyncLooper(const Functor &cb,AsyncType looper_type=AsyncType::ASYNC_SAFE ):
_looper_type(looper_type),
_stop(false),
_thread(std::thread(&AsyncLooper::threadEntry,this)), //1.创建一个新的线程，并让该线程执行类成员函数threadEntry。2.this 指针，就是将当前对象作为调用 threadEntry 函数的对象。
_callBack(cb){}

~AsyncLooper(){stop();}
//停止异步工作器
void stop(){
    _stop=true;
    _cond_con.notify_all(); //唤醒所有工作线程
    _thread.join();//等待线程结束
}
//生产者添加数据到缓冲区
void push(const char* data,size_t len){
    std::unique_lock<std::mutex> lock(_mutex);
    if(_looper_type==AsyncType::ASYNC_SAFE)
    //通过带谓词条件变量控制，若缓冲区剩余大小大于数据长度，可往下走，添加数据
      _cond_pro.wait(lock,[&](){return _pro_buf.writeAbleSize()>=len;});   //如果不满足条件，线程会释放锁并进入等待状态
    //向缓冲区添加数据
      _pro_buf.push(data,len);
      //环形消费者对缓冲区中的数据进行处理                                            
    _cond_con.notify_all();}
private:
//线程入口函数--对消费缓冲区中的数据进行处理，处理完毕后，初始化缓冲区，交换缓冲区
void threadEntry(){
    while(1){
      //为互斥锁设置一个生命周期，当缓冲区交换完毕后就解锁（不要对数据的处理加锁）
    {
        std::unique_lock<std::mutex> lock(_mutex);
        //停止标志为真且生产缓冲区无数据，这时候才能退出，否则生产缓冲区种有数据但不能被完全处理
        if (_stop == true && _pro_buf.empty()) { break; }
        //判断生产缓冲区有无数据或者工作线程是否处于停止状态，满足其一，消费者被唤醒，向下运行，否则释放锁进入等待状态
        _cond_con.wait(lock,[&](){return _stop||!_pro_buf.empty();});
        //把生产缓冲区中的数据转移到消费者缓冲区来
        _con_buf.swap(_pro_buf); 
    }
    //只有是安全状态，生产者才有可能阻塞，因而需要唤醒
    if(_looper_type==AsyncType::ASYNC_SAFE)
       _cond_pro.notify_all();
       //对消费缓冲区进行数据处理
       _callBack(_con_buf);
       //初始化消费缓冲区
       _con_buf.reset();
      
    }
    return;
}
private:
Functor _callBack; //具体对缓冲区数据进行处理的回调函数，由异步工作器使用者传入
private:
AsyncType _looper_type;//决定是否安全控制
std::atomic<bool> _stop;
Buffer _pro_buf; //生产缓冲区
Buffer _con_buf;  //消费缓冲区
std::mutex _mutex;  //互斥锁
std::condition_variable _cond_pro;  
std::condition_variable _cond_con;
std::thread _thread;

};

}
#endif